//Heyo, Frostii here. Almost all of the stuff that's *not* directly ported from 2.1 is in here, and is scripted by yours truly. 
//Please ask ina before taking any of this stuff for your own wads, it's really disrespectful to all the hard work we've done for 
//people to just steal our shit and use it without permission...
freeslot(
"MT_SOLEMERALD",
"MT_TRANSFORM_SOLEMERALD",
"S_SOLEMERALD1",
"S_SOLEMERALD2",
"S_SOLEMERALD3",
"S_SOLEMERALD4",
"S_SOLEMERALD5",
"S_SOLEMERALD6",
"S_SOLEMERALD7",
"MT_BLAZETAIL",
"MT_BLAZE_RUNFIRE",
"S_BLAZERUNFIRE",
"MT_BLAZE_JUMPFIRE",
"S_BLAZEJUMPFIRE",
"MT_BLAZEBOOSTAURA",
"S_BLAZEBOOSTAURA",
"MT_BLAZEBOOSTCIRCLE",
"S_BLAZEBOOSTCIRCLE",
"MT_BLAZEJUMPFLAME",
"S_BLAZEJUMPFLAME",
"MT_BLAZEBOOSTWIND",
"S_BLAZEBOOSTWIND",
"SPR_BLZF",
"SPR_BLZH",
"SPR_BSPF",
"SPR_BFPT",
"SPR_BJFR",
"SPR_INAE",
"SPR_BBCR",
"SPR_BWNE",
"S_BLAZETAIL_STAND",
"S_BLAZETAIL_SPRING",
"S_BLAZETAIL_FALL",
"S_BLAZETAIL_RUN",
"S_BLAZETAIL_INVIS",
"SFX_CATRL",
"SFX_BLZBST",
"SFX_BLZBTR",
"SFX_SECIR",
"SFX_SOLEMR",
"S_PLAY_BLAZE_HOVER",
"S_PLAY_BLAZE_SPINDASH",
"S_PLAY_BLAZE_SPIN",
"S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK",
"S_BPARTICLE",
"MT_BLAZE_SPINFIRE",
"S_BLAZESPINFIRE",
"MT_BLAZE_HOVERFIRE",
"S_BLAZEHOVERFIRE",
"MT_BLAZE_FLING",
"MT_BLAZE_DEADFLING",
"SPR_SEM1",
"SPR_SEM2",
"SPR_SEM3",
"SPR_SEM4",
"SPR_SEM5",
"SPR_SEM6",
"SPR_SEM7",
"SPR_BBFD"
)

local TWIRLSTATE = S_PLAY_ROLL
local FRACUNIT = FRACUNIT
local FRACBITS = FRACBITS
local TICRATE = TICRATE

sfxinfo[sfx_blzbst].caption = "Boosting"
sfxinfo[sfx_blzbtr].caption = "/"
sfxinfo[sfx_solemr].caption = "Sol Emerald Collected"
sfxinfo[sfx_secir].caption = "Circling emeralds"
sfxinfo[sfx_catrl].caption = "Meow"

mobjinfo[MT_BLAZEBOOSTWIND] = {
	doomednum = -1,
	spawnstate = S_BLAZEBOOSTWIND,
	flags = MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

states[S_BLAZEBOOSTWIND] = {
	sprite = SPR_BWNE,
	frame = A|FF_ANIMATE|TR_TRANS40|FF_PAPERSPRITE,
	var1 = 4,
	var2 = 4
}
mobjinfo[MT_SOLEMERALD] = {
	doomednum = -1,
	spawnstate = S_NULL,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SPECIAL,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
}
mobjinfo[MT_TRANSFORM_SOLEMERALD] = {
	doomednum = -1,
	spawnstate = S_NULL,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
}
mobjinfo[MT_BLAZETAIL] = {
	doomednum = -1,
	spawnstate = S_NULL,
	flags = MF_NOCLIPHEIGHT,
	dispoffset = 2,
	radius = 5*FRACUNIT,
	height = 5*FRACUNIT
}
mobjinfo[MT_BLAZEBOOSTAURA] = {
	doomednum = -1,
	spawnstate = S_BLAZEBOOSTAURA,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	dispoffset = 3,
	deathsound = sfx_ncspec
}
states[S_BLAZEBOOSTAURA] = {
	sprite = SPR_BBFD,
	frame = FF_FULLBRIGHT|FF_ANIMATE|TR_TRANS30,
	var1 = 3,
	var2 = 1
}
mobjinfo[MT_BLAZEBOOSTCIRCLE] = {
	doomednum = -1,
	spawnstate = S_BLAZEBOOSTCIRCLE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
states[S_BLAZEBOOSTCIRCLE] = {
	sprite = SPR_BBCR,
	frame = FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|TR_TRANS60,
	var2 = 2
}
mobjinfo[MT_BLAZEJUMPFLAME] = {
	doomednum = -1,
	spawnstate = S_INVISIBLE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
mobjinfo[MT_BLAZE_RUNFIRE] = {
	doomednum = -1,
	spawnstate = S_BLAZERUNFIRE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
states[S_BLAZERUNFIRE] = {
	sprite = SPR_BLZF,
	frame = FF_FULLBRIGHT|FF_ANIMATE|TR_TRANS30,
	var1 = 5,
	var2 = 1
}
mobjinfo[MT_BLAZE_JUMPFIRE] = {
	doomednum = -1,
	spawnstate = S_BLAZEJUMPFIRE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
states[S_BLAZEJUMPFIRE] = {
	sprite = SPR_BJFR,
	frame = FF_FULLBRIGHT|FF_ANIMATE|TR_TRANS40,
	var1 = 5,
	var2 = 2
}
states[S_BPARTICLE] = {
	sprite = SPR_BFPT,
	frame = FF_FULLBRIGHT|A|TR_TRANS30,
}
mobjinfo[MT_BLAZE_SPINFIRE] = {
	doomednum = -1,
	spawnstate = S_BLAZESPINFIRE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 1*FRACUNIT,
	height = 1*FRACUNIT,
	deathsound = sfx_ncspec
}
states[S_BLAZESPINFIRE] = {
	sprite = SPR_BSPF,
	frame = FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|TR_TRANS30,
	var1 = 5,
	var2 = 1
}
mobjinfo[MT_BLAZE_HOVERFIRE] = {
	doomednum = 3445,
	spawnstate = S_BLAZEHOVERFIRE,
	flags = MF_NOGRAVITY|MF_NOCLIPHEIGHT,
	spawnhealth = 50,
	radius = 17*FRACUNIT,
	height = 34*FRACUNIT,
	deathsound = sfx_ncspec
}
mobjinfo[MT_BLAZE_HOVERFIRE].name = "burst hover"--For battle hitfeed
mobjinfo[MT_BLAZE_FLING] = {
	doomednum = -1,
	spawnstate = S_PLAY_STND,
	flags = MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	deathstate = S_XPLD1,
	height = 5*FRACUNIT
}
mobjinfo[MT_BLAZE_DEADFLING] = {
	doomednum = -1,
	spawnstate = S_PLAY_STND,
	flags = MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	deathstate = S_NULL,
	height = 5*FRACUNIT
}
states[S_BLAZEHOVERFIRE] = {
	sprite = SPR_BLZH,
	frame = FF_FULLBRIGHT|FF_ANIMATE|TR_TRANS30,
	var1 = 5,
	var2 = 1
}
states[S_SOLEMERALD1] = {
	sprite = SPR_SEM1,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD2] = {
	sprite = SPR_SEM2,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD3] = {
	sprite = SPR_SEM3,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD4] = {
	sprite = SPR_SEM4,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD5] = {
	sprite = SPR_SEM5,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD6] = {
	sprite = SPR_SEM6,
	frame = FF_FULLBRIGHT|A
}
states[S_SOLEMERALD7] = {
	sprite = SPR_SEM7,
	frame = FF_FULLBRIGHT|A
}

local waterfactor = function(mo)
	if mo.eflags&MFE_UNDERWATER
		return 2
	end
	return 1
end

--inazuma here. first off we do a little bit of trolling. this is for 2.2.9's additive effect thingies. This basically turns it on or something.
local function set_add(mo) mo.blendmode = AST_ADD end

// Lach: self-explanatory
local function FixedSquare(n)
	return FixedMul(n, n)
end

// Lach: port of FV3_Rotate from source
local function FV3_Rotate(rotVecX, rotVecY, rotVecZ, axisVecX, axisVecY, axisVecZ, angle)
	local ux, uy, uz = FixedMul(axisVecX, rotVecX), FixedMul(axisVecX, rotVecY), FixedMul(axisVecX, rotVecZ)
	local vx, vy, vz = FixedMul(axisVecY, rotVecX), FixedMul(axisVecY, rotVecY), FixedMul(axisVecY, rotVecZ)
	local wx, wy, wz = FixedMul(axisVecZ, rotVecX), FixedMul(axisVecZ, rotVecY), FixedMul(axisVecZ, rotVecZ)
	local sa, ca = sin(angle), cos(angle)
	local ua = ux + vy + wz
	local ax, ay, az = FixedMul(axisVecX, ua), FixedMul(axisVecY, ua), FixedMul(axisVecZ, ua)
	local xs, ys, zs = FixedSquare(axisVecX), FixedSquare(axisVecY), FixedSquare(axisVecZ)
	local bx, by, bz = FixedMul(rotVecX, ys + zs), FixedMul(rotVecY, xs + zs), FixedMul(rotVecZ, xs + ys)
	local cx, cy, cz = FixedMul(axisVecX, vy + wz), FixedMul(axisVecY, ux + wz), FixedMul(axisVecZ, ux + vy)
	local dx, dy, dz = FixedMul(bx - cx, ca), FixedMul(by - cy, ca), FixedMul(bz - cz, ca)
	local ex, ey, ez = FixedMul(vz - wy, sa), FixedMul(wx - uz, sa), FixedMul(uy - vx, sa)
	
	return ax + dx + ex, ay + dy + ey, az + dz + ez
end

// Lach: translate object's momx/momy into 3-dimensional vector based on slope
local function GetMobjMovementVector(mo)
	local slope = mo.standingslope
	
	if slope
	and slope.zangle ~= 0
		return FV3_Rotate(mo.momx, mo.momy, 0, -slope.d.y, slope.d.x, 0, slope.zangle)
	end
	
	return mo.momx, mo.momy, mo.momz
end

//katsy: global function to get p speed depending on 2d mode
rawset(_G, "getrushcharpspeed", function(player)
	if twodlevel and not rphys then
		return FixedMul(player.runspeed*2/3, player.mo.scale)
	else
		return FixedMul(player.runspeed, player.mo.scale)
	end
end)
	
--first off, some PreThink stuff. most of this may not actually need to be in a PreThink, they're all just here to be safe.
addHook("PreThinkFrame", function(phuckshit)
	for p in players.iterate
		if not (p.mo and p.mo.skin == "blaze") continue end
		if p.fakenormalspeed == nil
			p.fakenormalspeed = skins[p.mo.skin].normalspeed
		end
		
		if p.blazeburstcharge == nil
			p.blazeburstcharge = 0
		end

		if P_IsObjectOnGround(p.mo) or (p.mo.eflags & MFE_JUSTHITFLOOR)
		or (p.powers[pw_carry]) or p.powers[pw_nocontrol]
		or P_PlayerInPain(p) or not p.mo.health or p.powers[pw_super] == 1
		or (p.solchar and p.solchar.istransformed == 1)
		or (p.gotflag) or (p.gotcrystal)
			p.blazehover = false
			p.blazehoverpower = 0
			p.blazehovertimer = 88
			p.mo.blazejumping = 0
		end

		if p.powers[pw_nocontrol] return end
		
		if p.dashspeed
			p.pflags = $ & ~ PF_THOKKED
		end
		
		--blaze spin-momentum.
		--MOSTLY-stolen from VEPH because fuck if i know how to code this shit on my own
		if (p.pflags & PF_SPINNING) and not (p.pflags & PF_STARTDASH) and not p.powers[pw_carry]
		and not (p.pflags & PF_STASIS)
			--restore full control while air spinning
			if not P_IsObjectOnGround(p.mo)
				p.pflags = $|PF_THOKKED & ~PF_NOJUMPDAMAGE
				
			--the actual special code
			else
				--spawn afterimages
				if p.mo.state == S_PLAY_BLAZE_SPIN
				or p.mo.state == S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK
					P_SpawnSpinMobj(p, MT_THOK)
				else
					local ghostmobj = P_SpawnGhostMobj(p.mo)
					ghostmobj.blendmode = AST_ADD
					ghostmobj.colorized = true
					ghostmobj.color = p.blazeflamecolor
					ghostmobj.fuse = 0
					ghostmobj.tics = 3
					ghostmobj.frame = $ & ~FF_TRANSMASK | FF_TRANS50
					ghostmobj.destscale = 0
					ghostmobj.scalespeed = p.mo.scale/12
					if ghostmobj.tracer and ghostmobj.tracer.valid
						ghostmobj.tracer.blendmode = AST_ADD
						ghostmobj.tracer.colorized = true
						ghostmobj.tracer.color = p.blazeflamecolor
						ghostmobj.tracer.fuse = 0
						ghostmobj.tracer.tics = 3
						ghostmobj.tracer.frame = $ & ~FF_TRANSMASK | FF_TRANS50
						ghostmobj.tracer.destscale = 0
						ghostmobj.tracer.scalespeed = p.mo.scale/12
					end
				end
				
				--the fun stuff
				local oldmomx = p.mo.momx
				local oldmomy = p.mo.momy
				local oldspeed = R_PointToDist2(0,0, oldmomx, oldmomy)
				local factor = max(max(81 - oldspeed*3/p.mo.scale, 12) - max(oldspeed*2/3/p.mo.scale - 36, 0), 6)
				
				local angle = p.cmd.angleturn<<16
				if p.mo.flags2 & MF2_TWOD or twodlevel
					angle = ANGLE_90
				end
				
				if not (p.gotflagdebuff)
					P_Thrust(p.mo, angle, p.cmd.forwardmove*p.mo.scale/factor)
					P_Thrust(p.mo, angle+ANGLE_90, -p.cmd.sidemove*p.mo.scale/factor)
					
					if R_PointToDist2(0,0, p.mo.momx, p.mo.momy) > oldspeed
						P_InstaThrust(p.mo, R_PointToAngle2(0,0, p.mo.momx, p.mo.momy), oldspeed)
					end
				end
			end
		end
		if not (p.mo.eflags & MFE_JUSTHITFLOOR)
			p.blazelaststate = p.mo.state
		end
	end
end)
addHook("PlayerSpawn", function(p)
	p.blazeburstcharge = 0
end)

--attacking while spinning or burning
addHook("PlayerCanDamage", function(p)
	if not (p.mo and p.mo.skin == "blaze") return end
	if p.mo.state == TWIRLSTATE or p.mo.state == S_PLAY_BLAZE_SPIN or p.mo.state == S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK or (p.blazeboosting)
		return true
	end
	if (p.pflags & PF_STARTDASH) and not p.solchar.istransformed
		return false
	end
end)

--start a boost
addHook("SpinSpecial", function(p)
	if p.mo.boat return true end
	if (p.mo.skin != "blaze") or (p.powers[pw_carry]) return nil end
	if ((p.blazeboosting) or (p.skidtime)) return true end
	if (p.blazeburstcharge >= TICRATE*2) and P_IsObjectOnGround(p.mo) and (p.speed > getrushcharpspeed(p))
	and not (p.gotflag or p.gotflagdebuff or p.gotcrystal) and not ((p.blazelaststate == TWIRLSTATE) and (p.pflags & PF_SPINDOWN))
		S_StopSoundByID(p.mo, sfx_spin)
		if not (p.blazeboosting)
			S_StartSound(p.mo, sfx_blzbst)
			p.blazeboosttimer = 1
		end
		S_StopSoundByID(p.mo, sfx_spin)
		if (p.panim == PA_ROLL)
			p.mo.state = S_PLAY_RUN
		end
		p.pflags = $|PF_SPINDOWN & ~PF_SPINNING
		p.blazeboosting = true
		return true
	end
	if (p.mo.eflags & MFE_JUSTHITFLOOR) and (p.panim != PA_ROLL) and (p.speed > FixedMul(4*FRACUNIT+FRACUNIT/2, p.mo.scale))
		p.pflags = $|PF_SPINNING|PF_SPINDOWN
		p.mo.state = TWIRLSTATE
		S_StartSound(p.mo, sfx_spin)
		return true
	end
end)

--main thinker
addHook("PlayerThink", function(p)
	if not (p.mo and p.mo.skin == "blaze") return end
	local mo = p.mo
	
	--air control stuff
	if p.mo.blazejumping or p.blazehover
		if p.mo.blazejumping
			p.thrustfactor = 9
		end
		if p.blazehover
			p.thrustfactor = 4
		end
	else
		p.thrustfactor = skins[p.mo.skin].thrustfactor
	end
	
	if not P_IsObjectOnGround(p.mo)
		p.blassped = FixedHypot(p.mo.momx, p.mo.momy)
	else
		p.blassped = nil
	end
	
	if p.powers[pw_carry] == CR_MACESPIN
		p.mo.state = S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK
	end
	
	if p.mo.blazeinspingap != nil and p.mo.blazeinspingap > 0
		p.mo.blazeinspingap = $ - 1
	end
	
	if p.mo.state == S_PLAY_BLAZE_SPIN and p.mo.blazeinspingap != nil and p.mo.blazeinspingap == 0
		p.mo.state = TWIRLSTATE
	end
	
	if not ((p.pflags & PF_THOKKED) and (p.pflags & PF_JUMPED) and (mo.state == S_PLAY_JUMP))
		mo.blazejumping = 0
	end
	
	if mo.blazejumping
		mo.blazejumping = $+1
		if mo.blazejumping < 10
			P_SetObjectMomZ(p.mo, FRACUNIT * 9/4 / waterfactor(mo), true)
		elseif mo.blazejumping > 40
			mo.blazejumping = 0
		end
	end
	--some funny haha fire FX for runnin'
	local fuckunit = p.mo.scale
	if P_IsObjectOnGround(p.mo) and (p.speed > getrushcharpspeed(p))
	and (p.panim == PA_RUN or p.panim == PA_ROLL) and not p.powers[pw_carry]
		if (rusheffects.value) and (leveltime % 2 == 0)
			local fire1 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.drawangle+FixedAngle(160*FRACUNIT), 20*FRACUNIT), P_ReturnThrustY(p.drawangle+FixedAngle(160*FRACUNIT), 20*FRACUNIT), 0, MT_BLAZE_RUNFIRE)
			if p.mo.eflags & MFE_UNDERWATER
				fire1.state = S_PARTICLE
				fire1.destscale = 7*p.mo.scale
			end
			fire1.color = p.blazeflamecolor
			fire1.fuse = 6
			P_SetObjectMomZ(fire1, 2*fuckunit+fuckunit/2, false)
			fire1.momx = p.mo.momx*3/4
			fire1.momy = p.mo.momy*3/4
			P_Thrust(fire1, R_PointToAngle2(p.mo.x, p.mo.y, fire1.x, fire1.y), 5*fuckunit)
			fire1.angle = R_PointToAngle2(p.mo.x, p.mo.y, fire1.x, fire1.y)
			fire1.scale = p.mo.scale - p.mo.scale/5
			local fire2 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.drawangle+FixedAngle(200*FRACUNIT), 20*FRACUNIT), P_ReturnThrustY(p.drawangle+FixedAngle(200*FRACUNIT), 20*FRACUNIT), 0, MT_BLAZE_RUNFIRE)
			if p.mo.eflags & MFE_UNDERWATER
				fire2.state = S_PARTICLE
				fire2.destscale = 7*p.mo.scale
			end
			fire2.color = p.blazeflamecolor
			fire2.fuse = 6
			P_SetObjectMomZ(fire2, 2*fuckunit+fuckunit/2, false)
			fire2.momx = p.mo.momx*3/4
			fire2.momy = p.mo.momy*3/4
			P_Thrust(fire2, R_PointToAngle2(p.mo.x, p.mo.y, fire2.x, fire2.y), 5*fuckunit)
			fire2.angle = R_PointToAngle2(p.mo.x, p.mo.y, fire2.x, fire2.y)
			fire2.scale = p.mo.scale - p.mo.scale/5
		end
	end
	--hover
	if p.blazehover
	and not (P_IsObjectOnGround(p.mo) or (p.mo.eflags & MFE_JUSTHITFLOOR)
	or (p.powers[pw_carry]) or p.powers[pw_nocontrol]
	or P_PlayerInPain(p) or not p.mo.health or p.powers[pw_super] == 1
	or (p.solchar and p.solchar.istransformed == 1))
		if p.cmd.buttons & BT_JUMP and (p.pflags & PF_JUMPED) and p.blazehovertimer > 0
			if not p.blazehoverpower
				p.blazehoverpower = 0
			end
			if (p.solchar.istransformed)
				p.blazehoverpower = FRACUNIT*3
			end
			if p.mo.momz*P_MobjFlip(p.mo) <= p.blazehoverpower
				p.blazehoverpower = $ - FRACUNIT/15
				p.blazehovertimer = $ - 1
				P_SetObjectMomZ(p.mo, p.blazehoverpower, false)
			end
			if (p.mo.state != S_PLAY_BLAZE_HOVER) and not (p.mo.state == S_PLAY_RUN and p.blazeboosting)
				p.mo.state = S_PLAY_BLAZE_HOVER
			end
			--flames
			local fuckunit = mo.scale
			local dist = 19
			local apart = 8
			local zheight = 4
			if not (p.flame1 and p.flame1.valid) and not (p.flame2 and p.flame2.valid)--leveltime % 7 == 0
				local flame1 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(flame1, p.drawangle+FixedAngle(180*FRACUNIT), dist*FRACUNIT)+
				P_ReturnThrustX(flame1, p.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
				P_ReturnThrustY(flame1, p.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
				P_ReturnThrustX(flame1, p.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
				-zheight*fuckunit*P_MobjFlip(p.mo), MT_BLAZE_HOVERFIRE)
				flame1.invuln = 7
				flame1.color = p.blazeflamecolor
				flame1.target = p.mo
				flame1.flame1 = true
				flame1.scale = p.mo.scale --+ p.mo.scale/4
				flame1.hit_sound = sfx_s3k70 --for battle
				p.flame1 = flame1
				local flame2 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(flame2, p.drawangle+FixedAngle(180*FRACUNIT), dist*FRACUNIT)+
				P_ReturnThrustX(flame1, p.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit),
				P_ReturnThrustY(flame2, p.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
				P_ReturnThrustY(flame1, p.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit), 
				-zheight*fuckunit*P_MobjFlip(p.mo), MT_BLAZE_HOVERFIRE)
				flame2.invuln = 7
				flame2.color = p.blazeflamecolor
				flame2.target = p.mo
				flame2.flame2 = true
				flame2.scale = p.mo.scale --+ p.mo.scale/4
				flame2.hit_sound = sfx_s3k70 --for battle
				p.flame2 = flame2			 
			end
		elseif not P_PlayerInPain(p)
			p.mo.state = S_PLAY_FALL
			p.blazehover = false
		end
	else
		if S_SoundPlaying(p.mo, sfx_blzhvr)
			S_StopSoundByID(p.mo, sfx_blzhvr)
		end
	end
	
	--spindash
	if (p.pflags & PF_STARTDASH) or (CBW_Battle and p.actionstate == 1)
		if not (p.mo.eflags & MFE_UNDERWATER)
			if leveltime % 5 == 0
				--print("phuck")
				local spin1 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.mo, p.drawangle+FixedAngle(140*FRACUNIT), 25*FRACUNIT), P_ReturnThrustY(p.mo, p.drawangle+FixedAngle(140*FRACUNIT), 25*FRACUNIT), 0, MT_BLAZE_SPINFIRE)
				spin1.fuse = 5
				spin1.angle = R_PointToAngle2(spin1.x, spin1.y, p.mo.x, p.mo.y)
				spin1.spin1 = true
				spin1.target = p.mo
				spin1.color = p.blazeflamecolor
				local spin2 = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.mo, p.drawangle+FixedAngle(220*FRACUNIT), 25*FRACUNIT), P_ReturnThrustY(p.mo, p.drawangle+FixedAngle(220*FRACUNIT), 25*FRACUNIT), 0, MT_BLAZE_SPINFIRE)
				spin2.fuse = 5
				spin2.angle = R_PointToAngle2(spin2.x, spin2.y, p.mo.x, p.mo.y)
				spin2.spin2 = true
				spin2.target = p.mo
				spin2.color = p.blazeflamecolor
			end
		else
			local i = 0 while i <= (leveltime%7)/2 // 1, 2, 3 or 4 particles
				local particle = P_SpawnMobj(p.mo.x, p.mo.y, p.mo.z, MT_SMALLBUBBLE)
				particle.fuse = 25
				particle.target = p.mo
				particle.destscale = (2*FRACUNIT)/3
				P_SetScale(particle, particle.destscale)
				if (p.mo.eflags & MFE_VERTICALFLIP) // readjust z position if needed
					particle.z = p.mo.z + p.mo.height - particle.height
				end
				local prandom = {}
				prandom[0] = P_RandomFixed()<<2 // P_RandomByte()<<10
				prandom[1] = P_RandomRange(-30, 30) // P_RandomRange(-ANG30/FRACUNIT, ANG30/FRACUNIT)*FRACUNIT
				prandom[2] = P_RandomFixed()<<3 // P_RandomByte()<<11
				P_SetObjectMomZ(particle, p.dashspeed/50 + prandom[0], false)
				P_InstaThrust(particle,
						p.mo.angle + (prandom[1]*ANG1),
						-FixedMul(p.dashspeed/12 + FRACUNIT + prandom[2], p.mo.scale))
				P_TryMove(particle, particle.x+particle.momx, particle.y+particle.momy, true)
			
				i = $+1
			end
		end
	end
	--burst mode
	if P_PlayerInPain(p) or (p.cmd.buttons & BT_CUSTOM1) or (p.playerstate != PST_LIVE)
	or p.gotflag or p.gotflagdebuff or p.gotcrystal or (p.powers[pw_super] == 1) or (p.skidtime)
	or (p.solchar and p.solchar.istransformed == 1) or p.exiting or p.powers[pw_carry] or (p.actionstate)
		if (p.blazeburstcharge >= TICRATE*2) and (p.playerstate == PST_LIVE) and not p.mo.boat
			S_StartSound(p.mo, sfx_s1ab)
		end
		p.blazeburstcharge = 0
	elseif (FixedHypot(p.rmomx, p.rmomy) > getrushcharpspeed(p)) and ((p.pflags & PF_JUMPED) or (P_IsObjectOnGround(p.mo)))
		p.blazeburstcharge = $+(TICRATE/35)
		if (p.solchar and p.solchar.istransformed) and (p.blazeburstcharge < TICRATE*2)
			p.blazeburstcharge = $+(TICRATE/35)
		end
		if not (leveltime%2) and (FixedHypot(p.rmomx, p.rmomy) > FixedMul(52<<FRACBITS, p.mo.scale)) and (p.blazeburstcharge < TICRATE*2)
			p.blazeburstcharge = $+(TICRATE/35) //charge 1.5x faster at high speeds
		end
	elseif P_IsObjectOnGround(p.mo) or (p.mo.eflags & MFE_JUSTHITFLOOR)
		if p.blazeburstcharge >= TICRATE*2
			S_StartSound(p.mo, sfx_s1ab)
		end
		p.blazeburstcharge = max(0, $-(TICRATE/12))
	end
	if (p.blazeburstcharge >= TICRATE*2)
		if (p.blazeburstcharge == TICRATE*2)
			S_StartSound(p.mo, sfx_prloop)
		else
			p.blazeburstcharge = 1+(TICRATE*2)
		end
		--print(p.blazeburstcharge)
	end
	p.pflags = $ & ~PF_DRILLING
	p.charability2 = CA2_SPINDASH
	if (p.blazeboosting)
		local moveang = R_PointToAngle2(0, 0, p.mo.momx, p.mo.momy)
		if CBW_Battle and abs(moveang - p.mo.angle) > ANG1*50 and p.blazeboosttimer > 5
			S_StartSound(p.mo, sfx_s1ab)
			p.blazeburstcharge = 0
			p.blazeboosting = false
			p.charflags = $&~SF_RUNONWATER
			if (p.solchar and p.solchar.istransformed)
				p.jumpfactor = FRACUNIT*4/3
			else
				p.jumpfactor = FRACUNIT
			end
			mo.momx = $ * 2/3
			mo.momy = $ * 2/3
		else
			if not (p.cmd.buttons & BT_SPIN) or (p.blazeburstcharge < TICRATE*2)
			or (p.skidtime) or (p.powers[pw_carry]) or (p.actionstate) or (p.guard)
			or (FixedHypot(p.mo.momx, p.mo.momy) <= 20*p.mo.scale and not P_IsObjectOnGround(p.mo))
				p.blazeboosting = false
				p.charflags = $&~SF_RUNONWATER
				if (p.solchar and p.solchar.istransformed)
					p.jumpfactor = FRACUNIT*4/3
				else
					p.jumpfactor = FRACUNIT
				end
				if rphys then
					mo.momx = $ * 3/5
					mo.momy = $ * 3/5
				end
				--p.hasnomomentum = false
			else
				local momx, momy, momz = GetMobjMovementVector(p.mo)
				p.charflags = $|SF_RUNONWATER
				p.pflags = $|PF_DRILLING & ~PF_SPINNING
				p.charability2 = CA2_NONE
				if p == displayplayer and not splitscreen
					P_StartQuake(FRACUNIT, 3)
				end
				if (rusheffects.value)
					local blazewind = P_SpawnMobjFromMobj(p.mo, P_RandomRange(-50, 50)*FRACUNIT, P_RandomRange(-50, 50)*FRACUNIT, P_RandomRange(0, 58)*FRACUNIT, MT_BLAZEBOOSTWIND)					
					blazewind.fuse = 20
					blazewind.momx = momx-momx/3
					blazewind.momy = momy-momy/3
					blazewind.momz = momz-momz/3
					blazewind.angle = R_PointToAngle2(p.mo.x, p.mo.y, p.mo.x+p.mo.momx, p.mo.y+p.mo.momy)
					blazewind.color = SKINCOLOR_NEON
					blazewind.scale = p.mo.scale+p.mo.scale/2
					blazewind.blendmode = AST_ADD
				end
				if p.solchar.istransformed or p.powers[pw_sneakers]
					if FixedHypot(p.mo.momx, p.mo.momy) <= 80*p.mo.scale --more accurate player.speed
						P_Thrust(p.mo, p.mo.angle, 80*p.mo.scale-FixedHypot(p.mo.momx, p.mo.momy))
					end
				else
					if FixedHypot(p.mo.momx, p.mo.momy) <= 60*p.mo.scale --more accurate player.speed
						P_Thrust(p.mo, p.mo.angle, 60*p.mo.scale-FixedHypot(p.mo.momx, p.mo.momy))
					end
				end
				if not (p.blazeboostmobj and p.blazeboostmobj.valid)
					local boost = P_SpawnMobjFromMobj(p.mo, P_ReturnThrustX(p.mo, R_PointToAngle2(p.mo.x, p.mo.y, p.mo.x+p.mo.momx, p.mo.y+p.mo.momy), 5*FRACUNIT), P_ReturnThrustY(p.mo, R_PointToAngle2(p.mo.x, p.mo.y, p.mo.x+p.mo.momx, p.mo.y+p.mo.momy), 5*FRACUNIT), 0, MT_BLAZEBOOSTAURA)
					boost.target = p.mo
					boost.color = p.blazeflamecolor
					p.blazeboostmobj = boost
				end
				if p.blazeboosttimer and (rusheffects.value) and (p.blazeboosttimer % 15 == 0)
					local circle = P_SpawnMobjFromMobj(p.mo, 0, 0, p.mo.height, MT_BLAZEBOOSTCIRCLE)
					circle.momx = momx/2
					circle.momy = momy/2
					circle.momz = momz/2
					circle.color = p.blazeflamecolor
					circle.fuse = 20
					circle.angle = R_PointToAngle2(p.mo.x, p.mo.y, p.mo.momx+p.mo.x, p.mo.momy+p.mo.y)+FixedAngle(90*FRACUNIT)
					circle.destscale = p.mo.scale*25
					circle.scalespeed = p.mo.scale/26
					circle.blendmode = AST_ADD
				end
				if not (p.solchar and p.solchar.istransformed)
					p.jumpfactor = FRACUNIT+FRACUNIT/3
				else
					p.jumpfactor = FRACUNIT*2
				end
				p.drawangle = R_PointToAngle2(p.mo.x, p.mo.y, p.mo.x+p.mo.momx, p.mo.y+p.mo.momy)
				if p.blazeboosttimer % (TICRATE+TICRATE/2) == 4
					S_StartSound(p.mo, sfx_blzbtr)
				end
				p.blazeboosttimer = $+1
				--p.hasnomomentum = true
			end
		end
	else
		if S_SoundPlaying(p.mo, sfx_blzbtr)
			S_StopSoundByID(p.mo, sfx_blzbtr)
		end
	end
	p.mo.blazefirebullshit = $ or 0
	p.mo.blazeisabitchassmotherfucker = $ or false
	if (p.mo.blazeisabitchassmotherfucker)
		p.mo.blazefirebullshit = $ + 1
	else
		p.mo.blazefirebullshit = 0
	end
	p.mo.blazeisabitchassmotherfucker = false
end)
--yoinking a bit of code from lach since layering bs is dumb
addHook("MobjThinker", function(mo)
	if not (mo and mo.valid and mo.health) return end
	if mo.target and mo.target.valid and mo.target.health and mo.target.skin == "blaze" and mo.target.player.blazeboosting
	local cameraToPlayerAngle = R_PointToAngle(mo.target.x, mo.target.y)
	if camera then cameraToPlayerAngle = R_PointToAngle2(camera.x + camera.momx, camera.y + camera.momy, mo.target.x, mo.target.y) end
	local rotation = ((cameraToPlayerAngle - mo.target.player.drawangle + ANGLE_202h) >> 29) + 1 // this gives us the frame rotation number for an 8-angle frame, as written in source 
	--P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.target.y+P_ReturnThrustY(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.target.z)
	if rotation != 5 and displayplayer then
		P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo.target, mo.target.player.drawangle, 5*mo.target.scale)+P_ReturnThrustX(mo, displayplayer.cmd.angleturn<<16, -6*mo.target.scale), mo.target.y+P_ReturnThrustY(mo.target, mo.target.player.drawangle, 5*mo.target.scale)+P_ReturnThrustY(mo.target, displayplayer.cmd.angleturn<<16, -6*mo.target.scale), mo.target.z)
	else
		P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo.target, mo.target.player.drawangle, 2*mo.target.scale), mo.target.y+P_ReturnThrustY(mo.target, mo.target.player.drawangle, 2*mo.target.scale), mo.target.z)
	end
	--P_TeleportMove(mo, mo.x+P_ReturnThrustX(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.y+P_ReturnThrustY(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.z)
	if (mo.eflags & MFE_VERTICALFLIP)
		mo.z = mo.target.z+(mo.target.height/2)
	end
	mo.rollangle = mo.target.rollangle
	mo.angle = mo.target.player.drawangle --R_PointToAngle2(mo.target.x, mo.target.y, mo.target.x+mo.target.momx, mo.target.y+mo.target.momy)
	mo.scale = mo.target.scale
	mo.spritexscale = FRACUNIT+FRACUNIT/2
	mo.spriteyscale = FRACUNIT+FRACUNIT/2
	--mo.state = mo.target.state
	--mo.frame = mo.target.frame|TR_TRANS30
	--mo.spritexscale = FRACUNIT/2
	--mo.spriteyscale = FRACUNIT/2
	else
		P_RemoveMobj(mo)
	end
end, MT_BLAZEBOOSTAURA)

addHook("MobjThinker", function(mo)
	if not (mo.target and mo.target.valid) return end
	if mo.BlazeSpecialGhost
		--P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.target.y+P_ReturnThrustY(mo, displayplayer.cmd.angleturn<<16, 1*FRACUNIT), mo.target.z)
		if not (mo.FuckYouScoobyDoo)
			P_TeleportMove(mo, mo.target.x, mo.target.y, mo.target.z)
		else
			P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.target.player.drawangle, mo.target.scale*3*-1), mo.target.y+P_ReturnThrustY(mo, mo.target.player.drawangle, mo.target.scale*3*-1), mo.target.z)
		end
		mo.rollangle = mo.target.rollangle
		mo.angle = mo.target.player.drawangle
		--mo.state = mo.target.state
		--mo.frame = mo.target.frame|TR_TRANS30
	end
end, MT_GHOST)

--do a normal roll in a zoomtube
addHook("ThinkFrame", do
	for player in players.iterate do
		if not (player.mo and player.mo.skin == "blaze"
		and player.powers[pw_carry] == CR_ZOOMTUBE) continue end
		//if not in the animation, set it
		if not (player.mo.state == S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK) then
			player.mo.state = S_PLAY_BLAZE_SPIN_2_BC_IM_LAZY_AS_FUCK
		end
		//set panim so the zoomtube doesn't change to rolling
		player.panim = PA_ROLL
	end
end)

--spin fire thinker
addHook("MobjThinker", function(mo)
	if not (mo.target and mo.target.valid and mo.target.health) return end
	local pmo = mo.target
	local p = mo.target.player
	local scale = mo.target.scale
	if not (pmo.eflags & MFE_VERTICALFLIP)
		if mo.spin1
			P_TeleportMove(mo, pmo.x+P_ReturnThrustX(pmo, p.drawangle+FixedAngle(140*FRACUNIT), 25*scale), pmo.y+P_ReturnThrustY(pmo, p.drawangle+FixedAngle(140*FRACUNIT), 25*scale), pmo.z)
			mo.angle = R_PointToAngle2(mo.x, mo.y, pmo.x, pmo.y)
		elseif mo.spin2
			P_TeleportMove(mo, pmo.x+P_ReturnThrustX(pmo, p.drawangle+FixedAngle(220*FRACUNIT), 25*scale), pmo.y+P_ReturnThrustY(pmo, p.drawangle+FixedAngle(220*FRACUNIT), 25*scale), pmo.z)
			mo.angle = R_PointToAngle2(mo.x, mo.y, pmo.x, pmo.y)
		end
	else
		if mo.spin1
			P_TeleportMove(mo, pmo.x+P_ReturnThrustX(pmo, p.drawangle+FixedAngle(140*FRACUNIT), 25*scale), pmo.y+P_ReturnThrustY(pmo, p.drawangle+FixedAngle(140*FRACUNIT), 25*scale), pmo.z+ mo.target.height - mo.height)
			mo.angle = R_PointToAngle2(mo.x, mo.y, pmo.x, pmo.y)
		elseif mo.spin2
			P_TeleportMove(mo, pmo.x+P_ReturnThrustX(pmo, p.drawangle+FixedAngle(220*FRACUNIT), 25*scale), pmo.y+P_ReturnThrustY(pmo, p.drawangle+FixedAngle(220*FRACUNIT), 25*scale), pmo.z+ mo.target.height - mo.height)
			mo.angle = R_PointToAngle2(mo.x, mo.y, pmo.x, pmo.y)
		end
	end
	if not ((p.pflags & PF_STARTDASH) or (CBW_Battle and p.actionstate == 1))
		P_RemoveMobj(mo)
	end
end, MT_BLAZE_SPINFIRE)

--start double jump/hover
addHook("AbilitySpecial", function(p)
	if not (p.mo.skin == "blaze" and p.gotflag <= 0
	and not (p.gotflagdebuff) and not p.gotcrystal) return end
	local mo = p.mo
	if p.exiting return end
	if (p.pflags & PF_THOKKED)
		if p.blazehovertimer and p.blazehovertimer > 0
			p.blazehover = true
			mo.state = S_PLAY_BLAZE_HOVER
			p.pflags = $|PF_JUMPED|PF_NOJUMPDAMAGE & ~PF_SPINNING
			S_StartSound(mo, sfx_blzhvr)
			p.blazehovertimer = max(0, $ - 9)
			
			mo.momz = $ / 2
		end
	else
		if p == displayplayer and not splitscreen
			P_StartQuake(2*FRACUNIT, 10)
		end
		
		local jumpheight = -2*FRACUNIT / waterfactor(mo)
		P_SetObjectMomZ(p.mo, jumpheight, false)
		
		p.pflags = $|PF_JUMPED|PF_THOKKED & ~PF_SPINNING & ~PF_NOJUMPDAMAGE
		mo.state = S_PLAY_JUMP
		mo.blazejumping = 1
		S_StartSound(mo, sfx_blzjmp)
	end
end)

--hover fire thinker
addHook("MobjThinker", function(mo)
	if not (mo.target) or (mo.target.skin != "blaze")
		pcall(P_RemoveMobj, mo)
		return
	end
	mo.scale = mo.target.scale
	if (mo.target.eflags & MFE_VERTICALFLIP)
		mo.eflags = $|MFE_VERTICALFLIP
	else
		mo.eflags = $ & ~ MFE_VERTICALFLIP
	end
	local fuckunit = mo.scale
	local dist = 19
	local apart = 8
	local zheight = 4
	if not (mo.eflags & MFE_VERTICALFLIP)
		if mo.flame1
			P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
			P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit), 
			mo.target.y+P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
			P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit), 
			mo.target.z-zheight*fuckunit)
		elseif mo.flame2
			P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
			P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
			mo.target.y+P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
			P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
			mo.target.z-zheight*fuckunit)
		end
	else
		if mo.flame1
			P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
			P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit), 
			mo.target.y+P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
			P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(-90*FRACUNIT), apart*fuckunit), 
			mo.target.z+zheight*fuckunit + mo.target.height - mo.height)
		elseif mo.flame2
			P_TeleportMove(mo, mo.target.x+P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
			P_ReturnThrustX(mo, mo.target.player.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
			mo.target.y+P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(180*FRACUNIT), dist*fuckunit)+
			P_ReturnThrustY(mo, mo.target.player.drawangle+FixedAngle(90*FRACUNIT), apart*fuckunit), 
			mo.target.z+zheight*fuckunit + mo.target.height - mo.height)
		end
	end
		
	if mo.invuln > 0 
		mo.invuln = $ - 1
	end

	if mo.invuln == 0 and mo.frame & FF_FRAMEMASK == A
		mo.frame = B | ($ & ~FF_FRAMEMASK)
	end
		
	if mo.target.eflags & MFE_UNDERWATER
		local fuk = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_PARTICLE)
		fuk.tics = 35
		fuk.scale = 1
		fuk.destscale = mo.scale*5
		fuk.scalespeed = mo.scale/12
		fuk.fuse = 18
		fuk.momz = FixedMul(mo.target.scale, 2*FRACUNIT)
		P_RemoveMobj(mo)
		return
	end
		
	if P_PlayerInPain(mo.target.player) or not (mo.target.player.blazehover)
		P_RemoveMobj(mo)
	end	
end, MT_BLAZE_HOVERFIRE)

--Blaze's Tail
--Fuck followmobjs btw, they are dumb and bad
local standframe = {
  [SPR2_STND] = true,
  [SPR2_WALK] = true,
  [SPR2_WAIT] = true,
  [SPR2_SKID] = true,
  [SPR2_RIDE] = true,
}
local runframe = {
  [SPR2_RUN_] = true,
  [SPR2_GLID] = true,
  [SPR2_TWIN] = true,
  [SPR2_EDGE] = true,
}
local fallframe = {
  [SPR2_FALL] = true,
  [SPR2_SPIN] = true
}
local springframe = {
  [SPR2_SPNG] = true,
  [SPR2_GASP] = true
}

local rollframe = {
	[SPR2_ROLL] = true
}

--tail thinker
addHook("FollowMobj", function(p, mobj)
	if not (p.mo and p.mo.valid and p.mo.health and p.mo.skin == "blaze" and p.solchar) return end
	local sprite2 = p.mo.sprite2 & ~FF_SPR2SUPER
	mobj.skin = "blaze"
	if (p.mo.eflags & MFE_VERTICALFLIP)
		mobj.eflags = $|MFE_VERTICALFLIP
	else
		mobj.eflags = $ & ~ MFE_VERTICALFLIP
	end
	if (sprite2 == SPR2_ROLL)
		if P_MobjFlip(p.mo) == 1
			P_TeleportMove(mobj, p.mo.x, p.mo.y, p.mo.z)
		else
			P_TeleportMove(mobj, p.mo.x, p.mo.y, p.mo.z+p.mo.height-mobj.height)
		end
	else
		Blaze_MoveTail(p, mobj)
	end
	mobj.flags2 = $|MF2_LINKDRAW
	mobj.color = p.mo.color
	if not (p.solchar.istransformed == 1)
		if standframe[sprite2]
			if mobj.state != S_BLAZETAIL_STAND
				mobj.state = S_BLAZETAIL_STAND
			end
		elseif runframe[sprite2]
			if mobj.state != S_BLAZETAIL_RUN
				mobj.state = S_BLAZETAIL_RUN
			end
		elseif fallframe[sprite2] 
			if mobj.state != S_BLAZETAIL_FALL
				mobj.state = S_BLAZETAIL_FALL
			end
		elseif springframe[sprite2] 
			if mobj.state != S_BLAZETAIL_SPRING
				mobj.state = S_BLAZETAIL_SPRING
			end
		elseif rollframe[sprite2] --and not (p.powers[pw_underwater])
			if mobj.state != TWIRLSTATE
				mobj.state = TWIRLSTATE
			end
			mobj.frame = p.mo.frame
			mobj.sprite2 = SPR2_FIRE
			mobj.flags2 = $&~MF2_LINKDRAW
			mobj.color = p.blazeflamecolor
			
		elseif mobj.state != S_BLAZETAIL_INVIS
			mobj.state = S_BLAZETAIL_INVIS
		end
	else
		mobj.state = S_BLAZETAIL_INVIS
	end
	if (p.mo.flags2 & MF2_DONTDRAW)
		mobj.flags2 = $|MF2_DONTDRAW
	else
		mobj.flags2 = $&~MF2_DONTDRAW
	end
	if mobj.sprite2 == SPR2_STND
		if p.mo.state == S_PLAY_JUMP or p.mo.state == TWIRLSTATE
			if mobj.anim_duration > 1
				mobj.anim_duration = 1
			end
		else
			if mobj.anim_duration > 4
				mobj.anim_duration = 4
			end
		end
	end
	mobj.spritexscale = p.mo.spritexscale
	mobj.spriteyscale = p.mo.spriteyscale
	mobj.rollangle = p.mo.rollangle
	mobj.scale = p.mo.scale
	
	// Lach: also copy render & frame flags
	mobj.frame = ($ & (FF_FRAMEMASK|FF_ANIMATE)) | (p.mo.frame & ~(FF_FRAMEMASK|FF_ANIMATE))
	if rollframe[sprite2]
		mobj.frame = $|FF_FULLBRIGHT
	end
	mobj.renderflags = p.mo.renderflags
	return true
end, MT_BLAZETAIL)

--damage enemies with the hover fire!
local function collZCheck(m,n) return m.z-15*m.scale < n.z+n.height and m.z+m.height-15*m.scale > n.z end
addHook("MobjMoveCollide", function(thing, tmthing)
	if not (thing and thing.valid and tmthing and tmthing.valid and tmthing.health and tmthing != thing.target) return end
	if collZCheck(thing, tmthing)
		P_DamageMobj(tmthing, thing, thing.target, DMG_FIRE)
	end
end, MT_BLAZE_HOVERFIRE)

--spindash thinker except katsy removed the spindash thinker
/*addHook("PlayerThink", function(player)
	if player.mo and player.mo.skin == "blaze"
		if player.mo.blazefirebullshit == nil
			player.mo.blazefirebullshit = 0
		end
		if player.mo.blazeisabitchassmotherfucker
			player.mo.blazefirebullshit = $ + 1
		else
			player.mo.blazefirebullshit = 0
		end
		player.mo.blazeisabitchassmotherfucker = false
	end
end)*/

--allow going under spin gaps while spinning
addHook("PlayerHeight", function(p)
	if not (p.mo and p.mo.skin == "blaze") return end
	if (p.panim == PA_ROLL) or (p.mo.state == S_PLAY_BLAZE_SPIN)
		return P_GetPlayerSpinHeight(p)
	end
	if (p.pflags & PF_STARTDASH)
		return P_GetPlayerHeight(p)
	end
end)
addHook("PlayerCanEnterSpinGaps", function(p)
	if not (p.mo and p.mo.skin == "blaze") return end
	if p.mo.state == TWIRLSTATE or p.mo.state == S_PLAY_BLAZE_SPIN
		if p.mo.state != S_PLAY_BLAZE_SPIN
			p.mo.state = S_PLAY_BLAZE_SPIN
		end
		p.pflags = $ | PF_JUMPSTASIS
		p.mo.blazeinspingap = 15
		return true
	end
end)

--partial fire immunity
addHook("ShouldDamage", function(mo, inf, src, dmg, dmgt)
    if not (mo and (mo.skin == "blaze") and mo.player) return end
	if (dmgt != DMG_FIRE) return end
	if mo.player.powers[pw_invulnerability] return end
	if mo.player.powers[pw_flashing] return end
	if (mo.player.gotflag or mo.player.gotflagdebuff or mo.player.gotcrystal) return end
	if ((inf and inf.valid and inf.player) or (src and src.valid and src.player)) return end
	if (mo.player.powers[pw_shield] & SH_PROTECTFIRE) return end
	if mo.player.solchar and mo.player.solchar.istransformed return end
	if mo.player.exiting return end
	if mo.boat and mo.boat.valid and mo.boat.health return end
	if inf
		if (rusheffects.value) and (leveltime % 5 == 0)
			local flame = P_SpawnMobjFromMobj(mo, P_RandomRange(-35, 35)*FRACUNIT, P_RandomRange(-35, 35)*FRACUNIT, P_RandomRange(-15, 15)*FRACUNIT, MT_PARTICLE)
			flame.state = S_FLAME
			flame.scale = mo.scale/4
			flame.fuse = 40
		end
		return false
	elseif not (inf or src)
		mo.blazeisabitchassmotherfucker = true
		if mo.player.rings > 1
			if mo.blazefirebullshit % 15 == 0
				mo.player.rings = $ - 1
				S_StartSound(mo, sfx_antiri)
			end
			if (rusheffects.value) and (leveltime % 5 == 0)
				local flame = P_SpawnMobjFromMobj(mo, P_RandomRange(-35, 35)*FRACUNIT, P_RandomRange(-35, 35)*FRACUNIT, P_RandomRange(-15, 15)*FRACUNIT, MT_PARTICLE)
				flame.state = S_FLAME
				flame.scale = mo.scale/4
				flame.fuse = 40
			end
			return false
		end
	end
end, MT_PLAYER)

addHook("MobjDeath", function(trg, inf, src)
	if not (trg.flags & MF_ENEMY) return end
	if not (trg and trg.valid and inf and inf.valid and inf.health and inf.player and inf.skin == "blaze" and inf.player.blazeboosting) return end
	local p = inf.player
	
	S_StartSound(inf, sfx_s3k49)
	trg.flags2 = $|MF2_DONTDRAW
//	mobjinfo[MT_BOWSER_FLING].spawnstate = trg.state --Copying it's spawnstate also copies that state's action , that's BEGGING for weird behaviour.
	local fling = P_SpawnMobjFromMobj(trg, 0, 0, 0, MT_BLAZE_FLING)
	if fling and fling.valid and trg and trg.valid --fucking errors for some reason if i dont do this shit
	
	--update: it still FUCKING DOES EVEN IF I DO ADD THESE CHECKS WHAT THE HELL AM I DOING WRONG FUCK
	
		trg.tics = -1
		fling.sprite = trg.sprite --Whatever sprite it's using now.
		fling.sprite2 = trg.sprite2 --just incase it's a player somehow.
		fling.frame = trg.frame --The frame it just used
		fling.angle = trg.angle --The angle it just used
		fling.color = trg.color
		fling.info.deathstate = S_CYBRAKDEMONVILEEXPLOSION1  --I'd recommend this, but for now, let's keep the deathstate behaviour, I guess!
		--fling.info.deathstate = trg.info.deathstate
		fling.nokilltimer = 3
		fling.info.deathsound = sfx_s3kb4
		S_StopSound(trg)
		--print("huhjnjdf")
		P_SetObjectMomZ(fling, 15*FRACUNIT, false)
		P_InstaThrust(fling, R_PointToAngle2(inf.x, inf.y, fling.x, fling.y), 63*FRACUNIT)
		--local storespawnhealth = trg.info.spawnhealth
		--trg.type = MT_BOWSER_DEADFLING
		--trg.info.spawnhealth = storespawnhealth
	end
end)
addHook("MobjThinker", function(mo)
	if not (mo and mo.valid and mo.health) return end
	if not (mo.secondphase)
		if mo.nokilltimer > 0
			mo.nokilltimer = $ - 1
		end
		--print(mo.info.deathstate)
		if P_IsObjectOnGround(mo) or (FixedHypot(mo.momx, mo.momy) == 0)
			--mo.rollangle = 0
			if mo.nokilltimer == 0
				mo.momx = 0
				mo.momy = 0
				mo.momz = 0
				mo.flags = $ | MF_NOGRAVITY
				local lmao = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BLAZE_FLING)
				lmao.sprite = mo.sprite
				lmao.sprite2 = mo.sprite2
				lmao.color = mo.color
				lmao.target = mo
				lmao.secondphase = true
				lmao.rollangle = mo.rollangle
				lmao.angle = mo.angle
				P_KillMobj(mo)
				mo.rollangle = 0
			end
		else
			mo.rollangle = $ + FixedAngle(20*FRACUNIT)
		end
	else
		if not (mo.target and mo.target.valid)
			P_RemoveMobj(mo)
		else
			mo.momx = 0
			mo.momz = 0
			mo.momy = 0
			if leveltime % 2 == 0
				mo.flags2 = $|MF2_DONTDRAW
			else
				mo.flags2 = $&~MF2_DONTDRAW
			end
		end
	end
end, MT_BLAZE_FLING)

addHook("JumpSpecial", function(player) //remove spin when jumping
	if not ((player.mo.skin == "blaze") and (player.pflags & PF_SPINNING) and ((player.mo.eflags & MFE_JUSTHITFLOOR) or P_IsObjectOnGround(player.mo)) and not (player.pflags & PF_JUMPDOWN) and not (player.pflags & PF_JUMPSTASIS)) return end
	player.pflags = $ & ~PF_SPINNING
end)
